<?php
/* [DoYouHaoBaby!] (C)Dianniu From 2010.
   Gtk Glade 提供模版引擎($)*/

!defined('DYHB_PATH') && exit;

class TemplateGtkGlade extends Template{

	static private $_oTemplateFileManager;
	static private $_arrParserDirs=array();
	private $_arrWidgetVariables=array();
	private $_arrTotalWidgets=array();
	private $_arrWidgetsTree=array();
	private $_arrWidgetIds=array();

	static public function addParserDir($sDir){
		A::STRING($sDir);
		A::DDIR($sDir);
		$sDirPath=G::tidyPath($sDir);
		if(!in_array($sDirPath,self::$_arrParserDirs)){self::$_arrParserDirs[]=$sDirPath;}
	}

	static public function clearParserDir(){
		$nCount=count(self::$_arrParserDirs);
		self::$_arrParserDirs=array();
		return $nCount;
	}

	static public function getDefaultParserManager(){
		$oParserManager=new TemplateObjProcessorManager();
		TemplateGtkGladeWidgetParser::regToProcessorManager($oParserManager);// 加入 GtkGladeWidget 分析器
		foreach(self::$_arrParserDirs as $sDirPath){$oParserManager->autoloadProcessor($sDirPath);}// 自动加入其他编译器
		return $oParserManager;
	}

	static public function createDefaultTemplateDirManger(){
		self::$_oTemplateFileManager=new TemplateFileManager();
	}

	static public function addTemplateDir($sDir){
		return self::$_oTemplateFileManager->addTemplateDir($sDir);
	}

	static public function clearTemplateDirs(){
		return self::$_oTemplateFileManager->clearTemplateDirs();
	}

	static public function createTemplateDirsMemento(){
		return self::$_oTemplateFileManager->createTemplateDirsMemento();
	}

	static public function setTemplateDirsMemento(array $arrMemento){
		return self::$_oTemplateFileManager->setTemplateDirsMemento($arrMemento);
	}

	static public function createTemplateDirIterator(){
		return self::$_oTemplateFileManager->createTemplateDirIterator();
	}

	static public function findTemplate($sTemplateFile){
		return self::$_oTemplateFileManager->findTemplate($sTemplateFile);
	}

	static public function trimWidgetId($WidgetId){
		return preg_replace('/@(View|TemplateController):([^:]+)/','\\2__\\1',$WidgetId);
	}

	static public function createGladeClassName($sGladeFile){
		if(!is_file($sGladeFile)){$sGladePath=self::findTemplate($sGladeFile);}
		else{$sGladePath=&$sGladeFile;}
		A::DFILE($sGladePath);
		return 'GtkGlade_'.md5_file($sGladePath);
	}

	static public function getWidgetVariableName($WidgetOrId){
		if(is_object($WidgetOrId)){
			A::INSTANCE($WidgetOrId);
			$sVariable=$WidgetOrId->getWidgetId();
		}
		else if(is_string($WidgetOrId)){
			$sVariable=$WidgetOrId;
		}
		else{
			A::ASSERT_(0,G::L('参数 $WidgetOrId 只能为 TemplateGtkGladeWidget对象  或  string','Dyhb',null));
		}
		$sVariable= self::trimWidgetId($sVariable);
		return str_replace('-','_',$sVariable);
	}

	static public function getWidgetCreateFunctionName($WidgetOrId){
		A::ISTHESE($WidgetOrId,array('TemplateGtkGladeWidget','string'),G::L('参数 $WidgetOrId 只能为 TemplateGtkGladeWidget对象  或  string','Dyhb',null));
		$sVariableName=self::getWidgetVariableName($WidgetOrId);
		return "create_{$sVariableName}";
	}

	public function create($GladeFile,$sWidgetId,array $arrObjectForSignal=array()){
		A::STRING($sWidgetId);
		if(!(is_string($GladeFile) && is_file($GladeFile))){
			if(is_array($GladeFile) && !empty($GladeFile['theme'])){
				$this->_sThemeName=$GladeFile['theme'];
			}else{
				$this->_sThemeName=TEMPLATE_NAME;
			}
			$GladeFile=self::findTemplate($GladeFile);
		}else{
			$this->_sThemeName=TEMPLATE_NAME;
		}
		A::DFILE($GladeFile,G::L('无法找到模板文件 %s','Dyhb',null,(is_array($GladeFile)? implode(' ',$GladeFile):$GladeFile)));
		$sCreateClassName=$this->loadGtkWidgetCreatorClass($GladeFile);// 载入窗体创建类
		//A::ISCLASS($sCreateClassName,'TemplateGtkWidgetCreator');
		$oCreator=new $sCreateClassName();// 创建 窗体创建对象
		$Callback=array($oCreator,'getWidget');
		A::CALLBACK($Callback,G::L('Glade模版文件“%s”的 编译文件失效。','Dyhb',null,$GladeFile));
		$oWidget=call_user_func_array($Callback,array($sWidgetId,$arrObjectForSignal));// 创建 窗体
		A::ISTHESE($oWidget,array('GtkWidget','null'));
		return $oWidget;
	}

	public function loadGtkWidgetCreatorClass($sGladePath){
		if(!is_file($sGladePath)){
			return null;
		}
		$sCompiledPath=$this->getCompiledPath($sGladePath);// 编译文件路径
		if($this->isCompiledFileExpired($sGladePath,$sCompiledPath)){// 检查编译文件有效
			parent::__construct();
			$sCompiledPath=$this->compile($sGladePath);
		}
		if(!is_file($sCompiledPath)){// 编译失败
			return null;
		}
		$sCreateClassName=self::createGladeClassName($sGladePath);// 载入 Compiled 文件
		if(!class_exists($sCreateClassName)){
			include $sCompiledPath;
		}
		return $sCreateClassName;
	}

	public function getWidget($sGladeFile,$sWidgetId,ViewGtk $oView=null,$bCreateNew=false){}

	protected function makeCompiledFile($sTemplatePath,$sCompiledPath,&$sCompiled){
		$sCompiledDir=dirname($sCompiledPath);// 创建 编译文件目录
		if(!is_dir($sCompiledDir)){
			if(!mkdir($sCompiledDir,0777,true)){
				A::ASSERT_(0);
			}
		}
		$sTemplatePathTwo=str_replace(G::tidyPath(DYHB_PATH),'\'.DYHB_PATH.\'',G::tidyPath($sTemplatePath));// 对编译进行替换，防止迁移路径错误
		$sTemplatePathTwo=str_replace(G::tidyPath(APP_PATH),'\'.APP_PATH.\'',G::tidyPath($sTemplatePathTwo));
		$sTemplatePathTwo="'$sTemplatePathTwo'";
		$sGladeClassName=self::createGladeClassName($sTemplatePath);
		$sWidgetTree=serialize($this->_arrWidgetsTree);
		$sWidgetIds=serialize($this->_arrWidgetIds);
		$nNow=date('Y-m-d H:i:s');
		$sCompiled="<?php 
/* DoYouHaoBaby Framework ".(G::L('模板缓存文件 生成时间：','Dyhb')).date('Y-m-d H:i:s', CURRENT_TIMESTAMP). "  */

!defined('DYHB_PATH') && exit; 
/**
 * DoYouHaoBaby Framework (Gtk窗体-创建器)模板编译文件
 *
 * < Do Not To Modify This File , Or This File Will Be Promptly Rebuilt! >
 *
 * @create {$nNow}
 * @access public
 */
class {$sGladeClassName} extends TemplateGtkWidgetCreator{

	/**
	 * 构造函数
	 */
	public function __construct(TemplateGtkGlade \$oTemplate=null){

		parent::__construct(\$oTemplate);
		\$this->_arrWidgetTree=unserialize('{$sWidgetTree}');
		\$this->_arrWidgetIds= unserialize('{$sWidgetIds}');
		\$this->_sTemplatePath={$sTemplatePathTwo};
	}

{$sCompiled}

}
";
		$sBrCode=IS_WIN?"\r\n":"\n";
		$sCompiled=str_replace(array("\r","\n"),'__dyhb_framework_pk_with_you__',$sCompiled);
		$sCompiled=preg_replace("/(__dyhb_framework_pk_with_you__)+/i",'__dyhb_framework_pk_with_you__',$sCompiled);
		$sCompiled=str_replace('__dyhb_framework_pk_with_you__',$sBrCode,$sCompiled);// 解决不同操作系统源代码换行混乱
		if(!file_put_contents($sCompiledPath,$sCompiled)){
			G::E(G::L('文件%不可写','Dyhb',null,$sCompiledPath));
		}
	}

	protected function compileTemplateObj(){
		$this->_arrTotalWidgets=array();
		$this->_arrWidgetsTree=array();
		$this->_arrWidgetIds=array();
		return $sCompiled=Template::compileTemplateObj();
	}

	public function addWidget_($sWidgetName,$sParentName=null){
		if($sParentName===null){
			if(isset($this->_arrTotalWidgets[$sWidgetName])){// 已经存在的节点
			}
			else{// 创建一个顶级节点
				$this->_arrWidgetsTree[$sWidgetName]=array();
				$this->_arrTotalWidgets[$sWidgetName]=&$this->_arrWidgetsTree[$sWidgetName];
			}
		}
		else{
			A::DARRAY($this->_arrTotalWidgets[$sParentName],NULL);
			$this->_arrTotalWidgets[$sParentName][$sWidgetName]=array();
			$this->_arrTotalWidgets[$sWidgetName]=&$this->_arrTotalWidgets[$sParentName][$sWidgetName];
		}
	}

	public function checkSameIdWidget_($sWidgetId,$sWidgetClass){
		A::STRING($sWidgetId);
		A::STRING($sWidgetClass);
		if(isset($this->_arrWidgetIds[$sWidgetId])){
			G::E(G::L('在同一个 Glade 文件中，不应该出现ID（Name）相同的窗体。相同ID的两个窗体的类型分别为：“%s”、“%s”','Dyhb',null,$this->_arrWidgetIds[$sWidgetId],$sWidgetClass));
		}
		$this->_arrWidgetIds[$sWidgetId]=$sWidgetClass;
	}

	static public function getWidgetCreator(GtkWidget $oWidget){
		return $oWidget->get_data('creator');
	}

}

/** 常量定义 */
if(class_exists('GObject')){
	if(defined('GObject::TYPE_STRING')){
		define('Gtk_TYPE_STRING',GObject::TYPE_STRING);
		define('Gtk_TYPE_LONG',GObject::TYPE_LONG);
		define('Gtk_TYPE_DOUBLE',GObject::TYPE_DOUBLE);
		define('Gtk_TYPE_INVALID',GObject::TYPE_INVALID);
		define('Gtk_TYPE_NONE',GObject::TYPE_NONE);
		define('Gtk_TYPE_INTERFACE',GObject::TYPE_INTERFACE);
		define('Gtk_TYPE_CHAR',GObject::TYPE_CHAR);
		define('Gtk_TYPE_BOOLEAN',GObject::TYPE_BOOLEAN);
		define('Gtk_TYPE_ENUM',GObject::TYPE_ENUM);
		define('Gtk_TYPE_FLAGS',GObject::TYPE_FLAGS);
		define('Gtk_TYPE_POINTER',GObject::TYPE_POINTER);
		define('Gtk_TYPE_BOXED',GObject::TYPE_BOXED);
		define('Gtk_TYPE_PARAM',GObject::TYPE_PARAM);
		define('Gtk_TYPE_OBJECT',GObject::TYPE_OBJECT);
		define('Gtk_TYPE_PHP_VALUE',GObject::TYPE_PHP_VALUE);
	}
	else{
		define('Gtk_TYPE_STRING',Gtk::TYPE_STRING);
		define('Gtk_TYPE_LONG',Gtk::TYPE_LONG);
		define('Gtk_TYPE_DOUBLE',Gtk::TYPE_DOUBLE);
		define('Gtk_TYPE_INVALID',Gtk::TYPE_INVALID);
		define('Gtk_TYPE_NONE',Gtk::TYPE_NONE);
		define('Gtk_TYPE_INTERFACE',Gtk::TYPE_INTERFACE);
		define('Gtk_TYPE_CHAR',Gtk::TYPE_CHAR);
		define('Gtk_TYPE_BOOLEAN',Gtk::TYPE_BOOLEAN);
		define('Gtk_TYPE_ENUM',Gtk::TYPE_ENUM);
		define('Gtk_TYPE_FLAGS',Gtk::TYPE_FLAGS);
		define('Gtk_TYPE_POINTER',Gtk::TYPE_POINTER);
		define('Gtk_TYPE_BOXED',Gtk::TYPE_BOXED);
		define('Gtk_TYPE_PARAM',Gtk::TYPE_PARAM);
		define('Gtk_TYPE_OBJECT',Gtk::TYPE_OBJECT);
		define('Gtk_TYPE_PHP_VALUE',Gtk::TYPE_PHP_VALUE);
	}
}

/** 创建缺省的 模板目录管理器 */
TemplateGtkGlade::createDefaultTemplateDirManger();
